﻿using System;
using System.Collections.Generic;
using Gp.Scripts.Core;
using Sirenix.OdinInspector;
using UnityEngine;

namespace Gp.Scripts.Core
{
    /// <summary>
    /// 关卡场景
    /// </summary>
    // [ExecuteAlways]
    public class SceneRoot : MonoBehaviour
    {
        private Dictionary<Type, SettleNodeRoot> _nodeRootMap;
        
        private static SceneRoot Instance { get; set; }
        
        private MainCharacterSpawner[] _spawners;
        
        private bool _isInitialized;

        private void Awake()
        {
            Global.RegisterEvent<Event_System.GameStart>(_ => Init());
            GameEntry.ManualInit();
        }

        private void Init()
        {
            if (Instance != null && Instance != this) { throw new Exception("Only one instance of SettleRoot is allowed."); }
            if (_isInitialized) return;
            _isInitialized = true;
            
            _nodeRootMap = new Dictionary<Type, SettleNodeRoot>();
            foreach (var node in GetComponentsInChildren<SettleNodeRoot>()) { _nodeRootMap[node.GetType()] = node; }
            _spawners = GetComponentsInChildren<MainCharacterSpawner>();
            
            // 由于存在直接在关卡内运行进行测试的需求，因此在关卡 Awake 的时候需要尝试进行全局初始化
            if (!Application.isPlaying) return;
            foreach (var nodes in _nodeRootMap.Values)
            {
                nodes.Init();
            }
        }
        

        public static T Get<T>() where T : SettleNodeRoot
        {
            if (!Instance)
            {
                Instance = FindObjectOfType<SceneRoot>()?? new GameObject(nameof(SceneRoot)).AddComponent<SceneRoot>();
                Instance.Init();
            }
            
            if (Instance._nodeRootMap.TryGetValue(typeof(T), out var ret) && ret)
            {
                return ret as T;
            }

            var com = SettleNodeRoot.CreateClassNode(typeof(T).Name, Instance.transform).AddComponent<T>();
            Instance._nodeRootMap[typeof(T)] = com;
            if (Application.isPlaying)
            {
                com.Init();
            }
            
            return com;
        }

        public static MainCharacterSpawner[] GetSpawners()
        {
            return Instance._spawners;
        }
    }
}